from pathlib import Path
from PIL import Image, ImageSequence
from io import BytesIO
from hashlib import md5
from webapp.config import Config
import piexif


def get_thumbnail_size(width, height):
    return Config.THUMB_WIDTH, round(height / width * Config.THUMB_WIDTH)


def gif2webp(file_path: Path, quality: int = None, make_thumb=True):
    """
    gif转webp动图
    :param file_path: gif图片路径
    :param quality: 图片质量，默认为 Config.WEBP_QUALITY = 90
    :param make_thumb: 是否生成缩略图
    :return:
    """
    if not quality:
        quality = Config.WEBP_QUALITY  # 90

    if quality > 95:
        quality = 95

    img_buffer = BytesIO()
    thumb_buffer = BytesIO()
    sequence = []
    thumb_sequence = []
    with Image.open(file_path) as gif:
        width, height = gif.size
        thumbnail_size = get_thumbnail_size(width, height)
        gif.convert("RGBA")
        for frame in ImageSequence.Iterator(gif):
            _frame = frame.copy()
            sequence.append(_frame)
            thumb_sequence.append(_frame.resize(thumbnail_size))

    sequence[0].save(img_buffer, format='webp', save_all=True, quality=quality, append_images=sequence[1:])
    if make_thumb:
        thumb_sequence[0].save(thumb_buffer, format='webp', save_all=True, quality=50, append_images=thumb_sequence[1: len(thumb_sequence) // 2])
    img_content = img_buffer.getvalue()
    return {
        'convert': True,
        'file_size': round(len(img_content) / 1024, 2),
        'md5': md5(img_content).hexdigest(),
        'width': width,
        'height': height,
        'img_buffer': img_buffer,
        'thumb_buffer': thumb_buffer,
    }


def file2webp(file_path: Path, quality: int = None, resize_factor: float = None, make_thumb=True):
    """
    图片转webp格式
    :param file_path:
    :param quality: 高于默认标准输出
    :param resize_factor: 缩放系数
    :param make_thumb: 是否生成缩略图
    :return:
    """
    if file_path.suffix.lower() == '.gif':
        return gif2webp(file_path, quality=quality, make_thumb=make_thumb)
    elif file_path.suffix.lower() == '.webp':
        return {'convert': False}
    else:
        file_obj = BytesIO(file_path.read_bytes())
        return img2webp(file_obj, quality, resize_factor, make_thumb)


def img2webp(obj: BytesIO,  quality: int = None, resize_factor: float = None, make_thumb=True)->dict:
    """
    图片转webp格式
    :param obj: 图片文件object
    :param quality: 高于默认标准输出
    :param resize_factor: 缩放系数
    :param make_thumb: 是否生成缩略图
    :return:
    """
    convert = False
    if not quality:
        quality = Config.WEBP_QUALITY  # 90
    if quality > 95:
        quality = 95

    img_buffer = BytesIO()
    thumb_buffer = BytesIO()
    with Image.open(obj) as img:
        obj.seek(0, 2)
        origin_size = obj.tell()
        img.convert('RGB')

        if 'exif' in img.info:
            exif_dict = piexif.load(img.info['exif'])
            orientation = exif_dict['0th'].pop(piexif.ImageIFD.Orientation, '')
            if orientation:
                # exif旋转信息
                img = img_rotate(img, orientation=orientation)

        width, height= img.size
        resolution = width * height
        if not resize_factor and resolution > 19440000:  # 4000 * 6000
            resize_factor = 0.8  # 3200 * 4800
        elif resolution <= 12000000:  # 如果图片小于 3000 * 4000，不缩小图片
            resize_factor = 1
        if resize_factor > 1:
            resize_factor = 1

        if resize_factor < 1:
            width = round(width * resize_factor)
            height = round(height * resize_factor)
            img = img.resize((width, height))

        if origin_size < 1024 * 1024:
            # 小于1M的图片不压缩
            img_content = obj.getvalue()
            img_buffer = BytesIO(img_content)
        else:
            img.save(img_buffer, 'webp', quality=quality)
            img_content = img_buffer.getvalue()
            convert = True

        if make_thumb:
            img.thumbnail(get_thumbnail_size(width, height))
            img.save(thumb_buffer, 'webp')
    file_size = len(img_content)
    return {
        'convert': convert,
        'origin_size': round(origin_size / 1024, 2),
        'file_size': round(file_size / 1024, 2),
        'size_rate': f'{round(file_size / origin_size * 100, 2)}%',
        'md5': md5(img_content).hexdigest(),
        'width': width,
        'height': height,
        'img_buffer': img_buffer,
        'thumb_buffer': thumb_buffer,
        'content_length': file_size,
    }


def img_rotate(img: Image, rotate: int = None, orientation: int = 0):
    """
    旋转图片
    :param img: 图片对象
    :param rotate: 手动设置顺时针旋转度数
    :param orientation: 根据图片exif信息设置旋转
        1：无旋转     8：顺时针90度      3：顺时针180度 6：顺时针270度
        2：水平翻转   7：顺时针90度+镜像  4：垂直翻转     5：顺时针270度+镜像
    :return: 图片对象
    """
    method = None
    if rotate is not None:
        if rotate == 90:
            orientation = 6
        elif rotate == 180:
            orientation = 3
        elif rotate == 270:
            orientation = 8
        else:
            # 0, 360 或其他度数
            orientation = 1

    if orientation == 1:
        pass
    elif orientation == 2:
        # 水平翻转
        method = Image.Transpose.FLIP_LEFT_RIGHT
    elif orientation == 3:
        # 顺时针旋转180度
        method = Image.Transpose.ROTATE_180
    elif orientation == 4:
        # 垂直翻转
        method = Image.Transpose.FLIP_TOP_BOTTOM
    elif orientation == 6:
        # 顺时针旋转270度 / 逆时针旋转90度
        method = Image.Transpose.ROTATE_270
    elif orientation == 8:
        # 顺时针旋转90度
        method = Image.Transpose.ROTATE_90

    if method:
        return img.transpose(method)

    return img
